/*
 * Menu: ActionScript > Value Object For Java Class
 * Key: M3+3
 * Kudos: Lance Woodson
 * DOM: http://localhost/org.eclipse.eclipsemonkey.lang.javascript
 */
var strategy;
var editor;
var source;
var originalLength;
var sourceLines;
var javaSource;
var javaPackage;
var javaClassName;
var javaVars = [];
var typeMappings = {
		'byte': 'Number',
		'short': 'Number',
		'int': 'Number',
		'long': 'Number',
		'float': 'Number',
		'double': 'Number',
		'Byte': 'Number',
		'Short': 'Number',
		'Integer': 'Number',
		'Long': 'Number',
		'Float': 'Number',
		'Double': 'Number',
		'BigDecimal': 'Number',
		'Long': 'Number',
		'String': 'String',
		getASForJava: function(jType) {
			var asType = this[jType];
			if (!asType) asType = jType;
			return asType;
		}
};
var metadataIndex;
var varIndex;
var methodIndex;

function main() {
	javaSource = gatherFileInput("Paste Java Source", "Paste in your java bean source code");
	var query = "Would you like to use:" +
	            "\n\n\t1.  Public properties with no accessors (default)" +
	            "\n\t2.  Private properties with accessors." +
	            "\n\nEnter 1 or 2.";
	strategy = gatherSelectionInput("Property Strategy", query, ["Public", "Private"]);
	editor = editors.activeEditor;
	asSource = editor.source;
	originalLength = asSource.length;
	asSourceLines = asSource.split("\n");
	sourceLines = javaSource.split("\n");
	
	extractJavaData();
	parseJsSource();
	
	injectCode();
	var newSource = asSourceLines.join("\n");
	editor.applyEdit(0, originalLength, newSource);
}

function injectCode() {
	// Handle metadata
	var metaDataStack = [
	    '\t[Bindable]\n',
	    '\t[RemoteClass(alias="' + javaPackage + '.' + javaClass + '")]'
	];
	insert(asSourceLines, metaDataStack, metadataIndex);
	
	// Handle vars
	var varStack = [];
	var pusher;
	if (strategy == "PRIVATE") {
		pusher = pushVariablePrivate;
	} else {
		pusher = pushVariablePublic;
	}
	for(var i = 0; i < javaVars.length; i++) {
		pusher(varStack, javaVars[i]);
	}
	insert(asSourceLines, varStack, varIndex);
	
	// Handle methods
	if (strategy == "PRIVATE") {
		var methodStack = [];
		for(var i = 0; i < javaVars.length; i++) {
			methodStack.push("\n\t\tpublic function get " + javaVars[i].name + "():" + javaVars[i].type + "\n");
			methodStack.push("\t\t{\n");
			methodStack.push("\t\t\treturn _" + javaVars[i].name + ";\n");
			methodStack.push("\t\t}\n");
			methodStack.push("\n");
			methodStack.push("\t\tpublic function set " + javaVars[i].name + "(value:" + javaVars[i].type + ")\n");
			methodStack.push("\t\t\t_" + javaVars[i].name + " = value;\n");
			methodStack.push("\t\t}");
			methodStack.push("\n");
		}
		methodStack.pop();
		
		insert(asSourceLines, methodStack, methodIndex);
	}
}

function pushVariablePublic(stack, varDef) {
	stack.push('\t\tpublic var ' + varDef.name + ':' + varDef.type + ';\n');
}

function pushVariablePrivate(stack, varDef) {
	stack.push('\t\tprivate var _' + varDef.name + ':' + varDef.type + ';\n');
}

function parseJsSource() {
	var bracketCount = 0;
	
	for(var i = 0; i < asSourceLines.length; i++) {

		if (/ class /.exec(asSourceLines[i])) {
			metadataIndex = i;
		}

		if (/\{/.exec(asSourceLines[i])) {
			bracketCount++;
			if (bracketCount = 2) {
				varIndex = i;
			}
		}
		
		if (/\}/.exec(asSourceLines[i])) {
			methodIndex = i + 1;
		}
	}
}


function extractJavaData() {
	var packageRegex = new RegExp("^package ([\\w\\.]+)");
	var classRegex = new RegExp("class (\\w+)");
	var variableRegex = new RegExp("(\\w+) (\\w+);");
	var bracketRegex = new RegExp("\\{");
	var bracketCount = 0;
	var varParsing = false;
	for(var i = 0; i < sourceLines.length; i++) {
		var packageMatch = packageRegex.exec(sourceLines[i]);
		if (packageMatch) javaPackage = packageMatch[1];
		var classMatch = classRegex.exec(sourceLines[i]);
		if (classMatch) { 
			javaClass = classMatch[1];
			varParsing = true;
		}
		if (varParsing) {
			// Constructor or method, assuming all vars parsed.			
			if (bracketRegex.exec(sourceLines[i])) {
				bracketCount++;
				if (bracketCount > 1) {					
					break;
				}
			}
			var varMatch = variableRegex.exec(sourceLines[i]);
			if (varMatch) {
				var jType = typeMappings.getASForJava(varMatch[1]);
				var jName = varMatch[2];
				var vData = {
						type: jType,
						name: jName,
						toString: function() {
							return this.name + ":" + this.type;
						}
				};
				javaVars.push(vData);
			}
		}
	}
}

function queryToPopulate(dataObject) {
	for(var property in dataObject) {
		dataObject[property] = gatherInput("Define Variables", "Enter a value for " + property, null);
	}
	return dataObject;
}

function gatherFileInput(label, queryString) {
	var filter = new Packages.org.eclipse.ui.views.navigator.ResourcePatternFilter();
	filter.setPatterns(["*.xml", "*.properties", "*.html", ".*", "*.gif", "*.jpg", "*.sql"]);
	var dialog = new Packages.org.eclipse.ui.dialogs.ElementTreeSelectionDialog(
			window.getShell(), 
			new Packages.org.eclipse.ui.model.WorkbenchLabelProvider(), 
			new Packages.org.eclipse.ui.model.BaseWorkbenchContentProvider());
	dialog.addFilter(filter);
	dialog.setTitle("Class Selection");
	dialog.setMessage("Select a java class to convert to actionscript");
	dialog.setInput(Packages.org.eclipse.core.resources.ResourcesPlugin.getWorkspace().getRoot());
	dialog.open();
	var selection = dialog.getResult()[0];
	var file = new Packages.java.io.File(selection.getLocationURI());
	var reader = new Packages.java.io.BufferedReader(new Packages.java.io.FileReader(file));
	var content = "";
	var text;
	while ((text = reader.readLine()) != null) {
		content = content + text + "\n"; 
	}
	reader.close();
	return content;
}

function gatherSelectionInput(label, queryString) {
	var choices = [
	    {
	    	label: 'Public properties',
	    	type: 'PUBLIC'
	    },
	    {
	    	label: 'Private properties with generated accessors',
	    	type: 'PRIVATE'
	    }
	];
	var o = {
			getImage: function(element) {
				return null;
			},
			getText: function(element) {
				return element.label;
			}
	};
	var labelProvider = Packages.org.eclipse.jface.viewers.ILabelProvider(o);
	var dialog = new Packages.org.eclipse.ui.dialogs.ElementListSelectionDialog(window.getShell(), labelProvider);
	dialog.setTitle(label);
	dialog.setMessage(queryString);
	dialog.setElements(choices);
	dialog.open();
	return dialog.getResult()[0].type;
}

function gatherInput(label, queryString, defaultValue) {
	dialog = new Packages.org.eclipse.jface.dialogs.InputDialog(
	          window.getShell(), 
	          label,
	          queryString,
	          null, null
	);
	result = dialog.open()
	// if (result == Packages.org.eclipse.jface.window.Window.OK)
		return dialog.getValue();
}
	
function debug(s) {
	Packages.org.eclipse.jface.dialogs.MessageDialog.openInformation(window.getShell(), "Monkey Debugging", s);
}

function insert(source, targetArr, position) {
	var target = targetArr;
	if (targetArr.join == undefined) {
		target = [targetArr];
	}
	target = target.join('');
	
	source.splice(position, 0, target);
}